<?php

header('Content-type: text/plain');

if(!defined('DEBUG')) define('DEBUG',false);

set_error_handler(array("CMS","Error_Exception_Handler"));

interface ICMS_Exception {
	public function getExceptionTrace();
	public function __toString();
}

class CMS_Error_Exception extends ErrorException implements ICMS_Exception {

	public function getExceptionTrace(){
		return get_class($this);
	}

	public function __construct(){
		$args = func_get_args();
		call_user_func_array(array('parent','__construct'), $args);
		error_log($this);
	}

	public function __toString(){
		return "{$this->message}\r\n{$this->file}\r\n{$this->line}\r\n";
	}

}

abstract class CMS_Exception extends Exception implements ICMS_Exception {

	public function getExceptionTrace(){
		return get_class($this);
	}

	public function __construct(){
		parent::__construct("", 0);
		error_log($this);
	}

	public function __toString(){
		return get_class($this) . "\r\n{$this->file}\r\n{$this->line}\r\n";
	}

}

class CMS_Core_Exception extends CMS_Exception {}

class CMS_File_Exception extends CMS_Exception {

	protected $_filename;
	protected $_filepath;

	public function __construct($filename, $filepath){
		$this->_filename = $filename;
		$this->_filepath = $filepath;
		parent::__construct();
	}

	public function __toString(){
		return "{$this->_filename}\t" . parent::__toString();
	}

}

class CMS_Start_Exception extends CMS_Exception {

	protected $_child;

	public function getExceptionTrace(){
		return parent::getExceptionTrace() . (isset($this->_child) ? " " . $this->_child->getExceptionTrace() : "");
	}

	public function __toString(){
		return $this->_child . parent::__toString();
	}

	public function __construct($message, $exception){
		$this->_child = $exception;
		parent::__construct($message);
	}

}

class CMS {

	// Singleton.

	protected $page;
	protected $output;

	protected static $instance;

	private static function createInstance(){
		CMS::$instance = new CMS();
		return CMS::$instance;
	}

	public static function getInstance(){
		if(!isset(CMS::$instance)){
			return CMS::createInstance();
		} else {
			return CMS::$instance;
		}
	}

	// Helper Functions

	public static function File($filename, $once = true){
		if(is_array($filename)){
			foreach($filename as $file){
				self::File($file, $once);
			}
		} else {
			$filename = strtolower($filename);
			$filepath = dirname(__FILE__) . '/' . $filename . '.php';
			if(file_exists($filepath)){
				if($once){
					require_once($filepath);
				} else {
					require($filepath);
				}
			} else {
				throw new CMS_File_Exception($filename, $filepath);
			}
		}
	}

	public static function Redirect($url){
		header("Location: {$url}");
		exit;
	}

	public function URL($path, $internal = true){
		$base = Site::getInstance()->url_root;
		$url = rtrim($base . ltrim($path, '/'),'/') . ($internal ? '/' : '');
		return $url;
	}

	public static function Error_Exception_Handler($errno, $errstr, $errfile, $errline ) {
		if($errno != E_STRICT){
		    throw new CMS_Error_Exception($errstr, 0, $errno, $errfile, $errline);
		}
	}

	public static function has_interface($class, $interface){
		$reflectionA = new ReflectionClass($class);
		return $reflectionA->implementsInterface($interface);
	}

	// CMS Functions

	private function start(){

		try {
			CMS::File(array('config','database','site','module','page', 'output'));

			Config::Load();

			Database::Load();

			Site::Load();

			Module::Load();

			$this->page = Page::Load_Page();

			$this->output =	Output::Load_Output();

		} catch (Config_Exception $e){

			CMS::File('install');

			$this->page = Install::Load_Page();

			$this->output =	Install::Load_Output();

		} catch (CMS_File_Exception $e){
			throw new CMS_Start_Exception("Core file not found", $e);

		} catch (Exception $e){
			throw new CMS_Start_Exception("Core function failed to load", $e);
		}


	}

	private function error($e){
		// A fatal exception has occured, so we can are going to abort.
		if(DEBUG){
			error_log("CMS Error: " . $e);
		} else {
			error_log("CMS Error: " . $e->getExceptionTrace());
		}
	}

	public static function Run($create = true){
		if($create){
			$cms = CMS::createInstance();
		} else {
			$cms = CMS::getInstance();
		}

		try {
			$cms->start();

			if(!(($cms->page) instanceof IPage) || !(($cms->output) instanceof IOutput)){
				throw new CMS_Core_Exception();
			}
			$cms->page->run();
			$data = $cms->page->output();
			$cms->output->display($data);

		} catch (Exception $e){
			$cms->error($e);
		}
		
	}




}
